﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using ThoughtWorks.QRCode.Codec;
using System.Windows.Forms;
using System.Drawing.Imaging;
using ZXing.Common;
using ZXing;
using ZXing.QrCode.Internal;
using System.Collections;

namespace MyPlatForms.Ctrls
{
    public class QrBuildHelper
    {
        public static Bitmap Gma_QRCode(string enCodeString)
        {
            Gma.QrCodeNet.Encoding.QrEncoder qrEncoder = new Gma.QrCodeNet.Encoding.QrEncoder(Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.L);
            Gma.QrCodeNet.Encoding.QrCode qrCode = qrEncoder.Encode(enCodeString);
            //qrEncoder.TryEncode(enCodeString, out qrCode);
            const int modelSizeInPixels = 4;

            Gma.QrCodeNet.Encoding.Windows.Render.FixedModuleSize moduleSize = new Gma.QrCodeNet.Encoding.Windows.Render.FixedModuleSize(modelSizeInPixels, Gma.QrCodeNet.Encoding.Windows.Render.QuietZoneModules.Zero);
            Gma.QrCodeNet.Encoding.Windows.Render.GraphicsRenderer render = new Gma.QrCodeNet.Encoding.Windows.Render.GraphicsRenderer(moduleSize, Brushes.Black, Brushes.White);

            Gma.QrCodeNet.Encoding.Windows.Render.DrawingSize dSize = render.SizeCalculator.GetSize(qrCode.Matrix.Width);
            Bitmap map = new Bitmap(dSize.CodeWidth, dSize.CodeWidth);
            Graphics g = Graphics.FromImage(map);
            render.Draw(g, qrCode.Matrix);

            return map;
        }

        public static Bitmap Gma_QRCode(string enCodeString,int newW,int newH)
        {
            Gma.QrCodeNet.Encoding.QrEncoder qrEncoder = new Gma.QrCodeNet.Encoding.QrEncoder(Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.L);
            Gma.QrCodeNet.Encoding.QrCode qrCode = qrEncoder.Encode(enCodeString);
            //qrEncoder.TryEncode(enCodeString, out qrCode);
            const int modelSizeInPixels = 4;

            Gma.QrCodeNet.Encoding.Windows.Render.FixedModuleSize moduleSize = new Gma.QrCodeNet.Encoding.Windows.Render.FixedModuleSize(modelSizeInPixels, Gma.QrCodeNet.Encoding.Windows.Render.QuietZoneModules.Zero);
            Gma.QrCodeNet.Encoding.Windows.Render.GraphicsRenderer render = new Gma.QrCodeNet.Encoding.Windows.Render.GraphicsRenderer(moduleSize, Brushes.Black, Brushes.White);

            //Gma.QrCodeNet.Encoding.Windows.Render.DrawingSize dSize = render.SizeCalculator.GetSize(qrCode.Matrix.Width);
            Gma.QrCodeNet.Encoding.Windows.Render.DrawingSize dSize = render.SizeCalculator.GetSize(newW);
            Bitmap map = new Bitmap(dSize.CodeWidth, dSize.CodeWidth);
            Graphics g = Graphics.FromImage(map);
            render.Draw(g, qrCode.Matrix);

            return map;
        }

        public static Bitmap ThoughtWorks_QRCode(string enCodeString)
        {
            System.Drawing.Bitmap bt;

            ThoughtWorks.QRCode.Codec.QRCodeEncoder qrCodeEncoder = new ThoughtWorks.QRCode.Codec.QRCodeEncoder();
            qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;//编码方式(注意：BYTE能支持中文，ALPHA_NUMERIC扫描出来的都是数字)
            qrCodeEncoder.QRCodeScale = 4;//大小(值越大生成的二维码图片像素越高)
            qrCodeEncoder.QRCodeVersion = 0;//版本(注意：设置为0主要是防止编码的字符串太长时发生错误)
            qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;//错误效验、错误更正(有4个等级)
            qrCodeEncoder.QRCodeBackgroundColor = Color.White;//背景色
            qrCodeEncoder.QRCodeForegroundColor = Color.Black;//前景色

            bt = qrCodeEncoder.Encode(enCodeString, Encoding.UTF8);

            return bt;
        }

        public static Bitmap ThoughtWorks_QRCode(string enCodeString,int newW,int newH)
        {
            System.Drawing.Bitmap bt;

            ThoughtWorks.QRCode.Codec.QRCodeEncoder qrCodeEncoder = new ThoughtWorks.QRCode.Codec.QRCodeEncoder();
            qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;//编码方式(注意：BYTE能支持中文，ALPHA_NUMERIC扫描出来的都是数字)
            qrCodeEncoder.QRCodeScale = 2;//大小(值越大生成的二维码图片像素越高)
            qrCodeEncoder.QRCodeVersion = 12;//版本(注意：设置为0主要是防止编码的字符串太长时发生错误)
            qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;//错误效验、错误更正(有4个等级)
            qrCodeEncoder.QRCodeBackgroundColor = Color.White;//背景色
            qrCodeEncoder.QRCodeForegroundColor = Color.Black;//前景色

            bt = qrCodeEncoder.Encode(enCodeString, Encoding.UTF8);

            return bt;
        }

        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="text">内容</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <returns></returns>
        public static Bitmap Zxing_QRCode(string text, int width, int height)
        {
            ZXing.BarcodeWriter writer = new ZXing.BarcodeWriter();
            writer.Format = ZXing.BarcodeFormat.QR_CODE;
            ZXing.QrCode.QrCodeEncodingOptions options = new ZXing.QrCode.QrCodeEncodingOptions()
            {
                DisableECI = true,//设置内容编码
                CharacterSet = "UTF-8",  //设置二维码的宽度和高度
                Width = width,
                Height = height,
                Margin = 0,//设置二维码的边距,单位不是固定像素
                ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.L,
                PureBarcode = true,
                //QrVersion = 20
            };
            
            writer.Options = options;
            Bitmap map = writer.Write(text);
            return map;
        }

        public static Bitmap Zxing_Create(string text, int width, int height,out int rectH)
        {
            rectH = 0;
            MultiFormatWriter writer = new MultiFormatWriter();
            Dictionary<EncodeHintType, object> hint = new Dictionary<EncodeHintType, object>();
            hint.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
            hint.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            hint.Add(EncodeHintType.DISABLE_ECI, true);
            hint.Add(EncodeHintType.HEIGHT, height);
            hint.Add(EncodeHintType.WIDTH, width);
            hint.Add(EncodeHintType.PURE_BARCODE, true);

            hint.Add(EncodeHintType.MARGIN, 0);

            //生成二维码 
            BitMatrix bm = writer.encode(text, BarcodeFormat.QR_CODE, width, height, hint);
            //bm = deleteWhite(bm);

            //获取二维码实际尺寸（去掉二维码两边空白后的实际尺寸）
            int[] rectangle = bm.getEnclosingRectangle();
            if (rectangle != null && rectangle.Length > 0)
            {
                rectH = rectangle[0];
            }
            BarcodeWriter barcodeWriter = new BarcodeWriter();
            Bitmap map = barcodeWriter.Write(bm);

            return map;

            //计算插入图片的大小和位置

            Bitmap bmpimg = new Bitmap(map.Width, map.Height, PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(bmpimg))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.DrawImage(map, 0, 0, width, height);
                //白底将二维码插入图片
                //g.FillRectangle(Brushes.White, middleL, middleT, middleW, middleH);
                //g.DrawImage(logo, middleL, middleT, middleW, middleH);
            }
            return bmpimg;
        }

        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="Content">内容文本</param>
        /// <param name="size">图片尺寸（像素）</param>
        /// <param name="margin">图片白边（像素）</param>
        /// <returns></returns>
        public static Bitmap TCreateQRCode(string Content, int size, int margin = 5)
        {
            QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
            qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
            qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;
            qrCodeEncoder.QRCodeScale = 5;
            qrCodeEncoder.QRCodeVersion = 0;

            try
            {
                System.Drawing.Image image = qrCodeEncoder.Encode(Content);
                int resWidth = size + 2 * margin;
                int resHeight = size + 2 * margin;
                // 核心就是这里新建一个bitmap对象然后将image在这里渲染
                Bitmap newBit = new Bitmap(resWidth, resHeight, PixelFormat.Format24bppRgb);//Format32bppRgb
                Graphics gg = Graphics.FromImage(newBit);

                gg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                gg.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
                gg.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                // 指定高质量的双三次插值法。执行预筛选以确保高质量的收缩。此模式可产生质量最高的转换图像。  
                gg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                // 指定高质量、低速度呈现。  
                gg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                gg.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;

                // 设置背景白色
                for (int y = 0; y < resWidth; y++)
                {
                    for (int x = 0; x < resHeight; x++)
                    {
                        newBit.SetPixel(x, y, Color.White);
                    }
                }

                // 设置黑色边框
                for (int i = 0; i < resWidth; i++)
                {
                    newBit.SetPixel(i, 0, Color.Black);
                    newBit.SetPixel(i, resWidth - 1, Color.Black);

                }

                for (int j = 0; j < resHeight; j++)
                {
                    newBit.SetPixel(0, j, Color.Black);
                    newBit.SetPixel(resHeight - 1, j, Color.Black);

                }
                gg.DrawImage(image, margin, margin, size, size);
                //newBit.Save(size.ToString() + ".png");
                return newBit;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static int GetLabelH(Control ctrl, string str, Font f)
        {
            Graphics g = ctrl.CreateGraphics();
            g.PageUnit = GraphicsUnit.Pixel;
            SizeF StrSize = g.MeasureString(str, f);
            return (int)StrSize.Height;
        }

        public static int GetLabelW(Control ctrl, string str, Font f)
        {
            Graphics g = ctrl.CreateGraphics();
            g.PageUnit = GraphicsUnit.Pixel;
            SizeF StrSize = g.MeasureString(str, f);
            return (int)StrSize.Width;
        }

        /// <summary>
        /// 生成带Logo的二维码
        /// </summary>
        /// <param name="text">内容</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        public static Bitmap Generate3(string strContent, int width, int height)
        {
            //生成二维码中的设置
            Hashtable hints = new Hashtable();
            hints.Add(EncodeHintType.CHARACTER_SET, "utf-8"); //编码
            hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); //容错率
            hints.Add(EncodeHintType.MARGIN, 0);  //二维码边框宽度，这里文档说设置0-4，但是设置后没有效果，不知原因，

            MultiFormatWriter writer = new MultiFormatWriter();
            Dictionary<EncodeHintType, object> hint = new Dictionary<EncodeHintType, object>();
            hint.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
            hint.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            hint.Add(EncodeHintType.MARGIN, 0);//旧版本不起作用，需要手动去除白边

            //生成二维码 
            BitMatrix bm = writer.encode(strContent, BarcodeFormat.QR_CODE, width, height, hint);
            bm = UpdateBit(bm, 1);  //生成新的bitMatrix

            //BufferedImage bi = BitMatrixToImageWriter.toBufferedImage(bm);
            //bi = zoomInImage(bi, size, size);//根据size放大、缩小生成的二维码
            //ImageIO.write(bi, "png", target); //生成二维码图片

            
            //bm = deleteWhite(bm);
            BarcodeWriter barcodeWriter = new BarcodeWriter();
            Bitmap map = barcodeWriter.Write(bm);

            return map;
            //获取二维码实际尺寸（去掉二维码两边空白后的实际尺寸）
            int[] rectangle = bm.getEnclosingRectangle();

            
            Bitmap bmpimg = new Bitmap(map.Width, map.Height, PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(bmpimg))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.DrawImage(map, 0, 0, width, height);
                //白底将二维码插入图片
                //g.FillRectangle(Brushes.White, middleL, middleT, middleW, middleH);
                //g.DrawImage(logo, middleL, middleT, middleW, middleH);
            }
            return bmpimg;
        }

        private static BitMatrix UpdateBit(BitMatrix matrix, int margin)
        {
            int tempM = margin * 2;
            int[] rec = matrix.getEnclosingRectangle();   //获取二维码图案的属性
            int resWidth = rec[2] + tempM;
            int resHeight = rec[3] + tempM;
            BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); // 按照自定义边框生成新的BitMatrix
            resMatrix.clear();
            for (int i = margin; i < resWidth - margin; i++)
            {   //循环，将二维码图案绘制到新的bitMatrix中
                for (int j = margin; j < resHeight - margin; j++)
                {
                    if (matrix[i + rec[0], j + rec[1]])
                        resMatrix[i, j] = true;

                    //if (matrix.get(i - margin + rec[0], j - margin + rec[1]))
                    //{
                    //    resMatrix.set(i, j);

                    //}
                }
            }
            return resMatrix;
        }

        /// <summary>
        /// 删除默认对应的空白
        /// </summary>
        /// <param name="matrix"></param>
        /// <returns></returns>
        private static BitMatrix deleteWhite(BitMatrix matrix)
        {
            int[] rec = matrix.getEnclosingRectangle();
            int resWidth = rec[2] + 1;
            int resHeight = rec[3] + 1;

            BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
            resMatrix.clear();
            for (int i = 0; i < resWidth; i++)
            {
                for (int j = 0; j < resHeight; j++)
                {
                    if (matrix[i + rec[0], j + rec[1]])
                        resMatrix[i, j] = true;
                }
            }
            return resMatrix;
        }


        // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
        // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
        // 假定初始输出的width为100，height为100
        public static BitMatrix RenderResult(ByteMatrix code, int width, int height, int quietZone)
        {
            ByteMatrix input = code;
            int inputWidth = input.Width;
            int inputHeight = input.Height;
            int qrWidth = inputWidth + (quietZone * 2);
            int qrHeight = inputHeight + (quietZone * 2);
            int outputWidth = Math.Max(width, qrWidth);
            int outputHeight = Math.Max(height, qrHeight);
            int multiple = Math.Min(outputWidth / qrWidth, outputHeight / qrHeight);

            outputWidth = qrWidth * multiple;// 改动点
            outputHeight = qrWidth * multiple;// 改动点

            // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
            // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
            // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
            // handle all the padding from 100x100 (the actual QR) up to 200x160.
            int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
            int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
            leftPadding = 0;//改动点
            topPadding = 0;//改动点
            BitMatrix output = new BitMatrix(outputWidth, outputHeight);
            for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple)
            {
                // Write the contents of this row of the barcode
                for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple)
                {
                    if (input[inputX, inputY] == 1)
                    {
                        output.setRegion(outputX, outputY, multiple, multiple);
                    }
                }
            }

            return output;
        }

    }
}
